/*
 * Copyright (C) 2011 Project R'yleh Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.Arkham;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.util.Log;
import android.view.View;

public class Mesh
{
	private final static String TAG = Mesh.class.getSimpleName();
	
	protected Bitmap mBitmap;
	

	protected boolean mShouldLoadTexture = false;
	
	protected int mTexID[] = {-1};
	protected int mSpriteID[];
	protected int mNumIndices = -1;
	
	protected FloatBuffer mVertexBuffer = null;
	
	protected ShortBuffer mIndexBuffer = null;
	
	
	protected FloatBuffer mTextureBuffer = null;
	
	protected FloatBuffer mColorBuffer = null;
	protected int mTickCount;
	
	protected Context context;
	
	protected final float[] mRGBA = new float[] {1.0f,1.0f,1.0f, 1.0f};
	
	protected float[] mTranslate = {0.0f, 0.0f, 0.0f};
	protected float[] mRotation = {0.0f, 0.0f, 0.0f};
	//private float[] mScale = {1.0f , 1.0f, 1.0f};
	
	protected int frameOffset;
	protected int numberFrame;
	protected int xSize, ySize;

	protected int[] mPixelData ;
	protected ByteBuffer mPixelByte;
	protected IntBuffer mPixelColor;
	protected int xOffset = 0; 
	protected int yOffset = 0; 
	
	
	protected boolean shouldUpdateTexCord = false;
	int numXtile ;
	int numYtile;
	
	protected boolean isClickable = false;
	protected boolean isClicked = false;
	public float xDim,yDim;
	public int indexID;
	public float modelView[];
	
	protected void OnDraw(GL10 gl)
	{
		
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		((GL11)gl).glGetFloatv(GL11.GL_MODELVIEW_MATRIX, modelView, 0);
		gl.glFrontFace(GL10.GL_CCW);
		gl.glColor4f(mRGBA[0], mRGBA[1], mRGBA[2], mRGBA[3]);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
		
		
		if(mColorBuffer != null)
		{
			gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
			gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
		}
		
		if (mShouldLoadTexture)
		{
			loadGLTexture(gl);
			
			mShouldLoadTexture = false;			
		}
		
		if(mTexID[0] != -1 && mTextureBuffer != null)
		{
			gl.glEnable(GL10.GL_TEXTURE_2D);
			gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexID[0]);
			gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
			
			
		}
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glPushMatrix();
		gl.glTranslatef(mTranslate[0], mTranslate[1], mTranslate[2]);
		gl.glRotatef(mRotation[0], 1, 0, 0 );
		gl.glRotatef(mRotation[1], 0, 1, 0 );
		gl.glRotatef(mRotation[2], 0, 0, 1 );
		
		//gl.glScalef(mScale[0],mScale[1], mScale[2]);
		
		gl.glDrawElements(GL10.GL_TRIANGLES, mNumIndices,
						  GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
		gl.glPopMatrix();
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		
		
		if(mTexID[0] != -1 && mTextureBuffer != null)
		{
			gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			gl.glDisable(GL10.GL_TEXTURE_2D);
		}
		


		gl.glFinish();
	}
	
	protected void loadGLTexture(GL10 gl)
	{
		modelView = new float[16];
		// Generate one texture pointer...
		int[] textures = new int[1];
		gl.glGenTextures(textures.length, textures, 0);
		mTexID[0] = textures[0];
		
		
		int err = gl.glGetError();
		if(err != GL10.GL_NO_ERROR)
			Log.e(TAG, " GL GEN tex error: " + GLU.gluErrorString(err));
		gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexID[0]);
		
		 err = gl.glGetError();
		if(err != GL10.GL_NO_ERROR)
			Log.e(TAG, " GL Bind tex error: " + GLU.gluErrorString(err));
		
		assert err == GL10.GL_NO_ERROR;

		// Create Nearest Filtered Texture
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
		

	
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
		//gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
			err = gl.glGetError();
			if(err != GL10.GL_NO_ERROR)
				Log.e(TAG, " glTexParameterf error: " + GLU.gluErrorString(err));
			
			assert err == GL10.GL_NO_ERROR;

//			gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA,mBitmap.getWidth(), mBitmap.getHeight(), 0,GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, mPixelColor);
//			err = gl.glGetError();
//			if(err != GL10.GL_NO_ERROR)
//				Log.e(TAG, " glTexParameterf error: " + GLU.gluErrorString(err));
			
		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
	
			
		assert err == GL10.GL_NO_ERROR;
		//mBitmap.recycle();
		
		
	
		
	}

	
	
	
	protected void setVertices(float[] vertices)
	{
		//mVertex = vertices;
		ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length *4);
		vbb.order(ByteOrder.nativeOrder());
		mVertexBuffer = vbb.asFloatBuffer();
		mVertexBuffer.put(vertices);
		mVertexBuffer.position(0);
	}
	
	protected void setIndices(short[] indices)
	{
		//mIndex = indices;
		ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
		ibb.order(ByteOrder.nativeOrder());
		mIndexBuffer = ibb.asShortBuffer();
		mIndexBuffer.put(indices);
		mIndexBuffer.position(0);
		mNumIndices = indices.length;
		
	}
	
	
	
	protected void setTexCoords(float[] textureCoords)
	{
	     //mTexCoord = textureCoords;
		ByteBuffer texBuff = ByteBuffer.allocateDirect(textureCoords.length *4);
		texBuff.order(ByteOrder.nativeOrder());
		mTextureBuffer = texBuff.asFloatBuffer();
		mTextureBuffer.put(textureCoords);
		mTextureBuffer.position(0);
		
		
	}
	
	protected void setColor(float r, float g, float b, float a)
	{
		mRGBA[0] = r;
		mRGBA[1] = g;
		mRGBA[2] = b;
		mRGBA[3] = a;
			
	}
	
	protected void setColorBuffer(float[] colors)
	{
		ByteBuffer cbb =  ByteBuffer.allocateDirect(colors.length * 4);
		cbb.order(ByteOrder.nativeOrder());
		mColorBuffer = cbb.asFloatBuffer();
		mColorBuffer.put(colors);
		mColorBuffer.position(0);

	}

	protected void setTranslation( float x, float y, float z)
	{
		 mTranslate[0] = x;
		 mTranslate[1] = y;
		 mTranslate[2] = z;
		
	}
	
	
	protected void setRotation(float rx, float ry, float rz)
	{
		mRotation[0] = rx;
		mRotation[1] = ry;
		mRotation[2] = rz;	
	}
	
	protected void updateRotation(float rx, float ry, float rz)
	{
		mRotation[0] += rx;
		if(mRotation[0] >= 360.0f)
			mRotation[0] -= 360.0f;
		mRotation[1] += ry;
		if(mRotation[1] >= 360.0f)
			mRotation[1] -= 360.0f;
		mRotation[2] += rz;
		if(mRotation[2] >= 360.0f)
			mRotation[2] -= 360.0f;
	}
	
	

	public void loadBitmap(Bitmap bitmap)
	{
		this.mBitmap = bitmap;
		mShouldLoadTexture = true;
		
	}
	
	protected float[] TranslateTexture(GL10 gl ,int xOff, int yOff, float[] inTexCord)
	{
		/*
		for(int i = 0; i < inTexCord.length;i += 2)
		{
		   Log.i(TAG, "Before: inTexCord[" +i +"] " + inTexCord[i] + " inTexCord["+(i + 1)+"] " + inTexCord[i +1]);
		   // Log.i(TAG, "X ratio " + (mBitmap.getWidth()/(float)xSize) +" Y Ratio: " + (mBitmap.getHeight() / (float)ySize));
			inTexCord[i] =  xOff * (mBitmap.getWidth()/(float)xSize);
			inTexCord[i +1] = yOff *(mBitmap.getHeight() / ySize);
			Log.i(TAG, "After: inTexCord[" +i +"] " + inTexCord[i] + " inTexCord["+(i + 1)+"] " + inTexCord[i +1]);
			
		}
		*/
		return inTexCord;
	}
	
	
	
	
	
	protected void onUpdate(GL10 gl, int tickCount)
	{
		
		if(tickCount % 5 == 0)
		{
			if(xOffset >= numXtile)
				xOffset = 0;
			else
				xOffset++ ;
		
		//Log.i(TAG,"X Offset " + xOffset);
		}
		xOffset /= 2;
	}
	
	public void setSprite(int numFrames, int xOff, int yOff)
	{
		numberFrame = numFrames;
		xSize = xOff;
		ySize = yOff;
	}
	
	protected void setTileSize(int xsize, int ysize)
	{
		xSize = xsize;
		ySize = ysize;
	}
	
	protected void scaleTexutureCoordinates(GL10 gl)
	{
		gl.glMatrixMode(GL10.GL_TEXTURE);
		gl.glLoadIdentity();
		gl.glPushMatrix();
		gl.glScalef(1.0f/(mBitmap.getWidth()/ xSize ), 1.0f/(mBitmap.getHeight()/ ySize ), 1.0f);
		gl.glPopMatrix();
		shouldUpdateTexCord = true;
		
	}
	
	protected float [] updateTextureCoords(float [] inTexCord)
	{
		
		for(int i = 0; i < inTexCord.length;i += 2)
		{
	
		   //Log.i(TAG, "Before: inTexCord[" +i +"] " + inTexCord[i] + " inTexCord["+(i + 1)+"] " + inTexCord[i +1]);

		   // Log.i(TAG, "X ratio " + (mBitmap.getWidth()/(float)xSize) +" Y Ratio: " + (mBitmap.getHeight() / (float)ySize));

			inTexCord[i] /=  mBitmap.getWidth() / xSize;

			inTexCord[i +1] /=     mBitmap.getHeight() / ySize;

			Log.i(TAG, "After: inTexCord[" +i +"] " + inTexCord[i] + " inTexCord["+(i + 1)+"] " + inTexCord[i +1]);
 
			 
		}
			 
			 			return inTexCord;
	
	
	}
	public void setContext(Context inContext)
	{
		context = inContext;
	}
	
	public void clearMesh(GL10 gl)
	{
		gl.glDeleteTextures(mTexID.length, mTexID, 0);
		
		if(mVertexBuffer != null)
		{
		mVertexBuffer.clear();
		 mVertexBuffer = null;
		}
		
		 if(mIndexBuffer != null)
		{
		 mIndexBuffer.clear();
		 mIndexBuffer = null;
		}
		
		if(mTextureBuffer != null)
		{
		mTextureBuffer.clear();
		mTextureBuffer = null;
		}
		
		if(mColorBuffer != null)
		{
		mColorBuffer.clear();
		mColorBuffer = null;
		}
		
	}
	
	public void setClickable(boolean value)
	{
		isClickable = value;
	}
	public boolean getClickable()
	{
		return isClickable;
	}
	
	public void setIsClicked(boolean value)
	{
		isClicked = value;
	}
	
	public boolean getIsClicked()
	{
		return isClicked;
	}
	
	
	
	public float[] getModelViewMatrix()
	{
		
		
		
	
		//gl.glLoadIdentity();
		
		
		return modelView;
	
		
		
	}
	
	

}
